package me.leon.misc.net

import java.net.Socket
import me.leon.encode.punyCode
import me.leon.ext.fromJson
import me.leon.ext.readFromNet

/**
 * @author Leon
 * @since 2023-02-23 11:11
 * @email deadogone@gmail.com
 */
object Whois {
    const val API_RDAP_CONFIG = "https://data.iana.org/rdap/dns.json"
    const val ENTITY_ROLE_REGISTRAR = "registrar"
    const val ENTITY_ROLE_REGISTRANT = "registrant"
    const val ENTITY_ROLE_ADMINISTRATIVE = "administrative"
    const val ENTITY_ROLE_TECHNICAL = "technical"
    const val ENTITY_ROLE_ABUSE = "abuse"
    private var _services: List<List<List<String>>> = mutableListOf()
    private val services: List<List<List<String>>>
        get() {
            if (_services.isNotEmpty()) {
                return _services
            }
            _services =
                API_RDAP_CONFIG.readFromNet().fromJson(WhoisServiceBean::class.java).services
            return _services
        }

    fun parse(domain: String): Rdap? {
        val top = domain.substringAfterLast(".").lowercase().punyCode()
        val api = services.find { it.first().contains(top) }?.last()?.last()
        return api?.let {
            "$api/domain/${domain.punyCode()}".readFromNet().fromJson(Rdap::class.java)
        }
    }
}

private const val WHOIS_CHINESE_TLD = "whois.gtld.knet.cn"
private const val WHOIS_CHINESE_TLD2 = "whois.ngtld.cn"
private const val WHOIS_FOREIGN_TLD = "whois.centralnic.com"
private const val WHOIS_RIPE_NET = "whois.ripe.net"

val whoisServers =
    mapOf(
        // Whois服务器，参考：http://www.iana.org/domains/root/db
        "ac" to "whois.nic.ac",
        "ae" to "whois.aeda.net.ae",
        "aero" to "whois.aero",
        "af" to "whois.nic.af",
        "ag" to "whois.nic.ag",
        "al" to WHOIS_RIPE_NET,
        "am" to "whois.amnic.net",
        "as" to "whois.nic.as",
        "asia" to "whois.nic.asia",
        "at" to "whois.nic.at",
        "au" to "whois.aunic.net",
        "ax" to "whois.ax",
        "az" to WHOIS_RIPE_NET,
        "ba" to WHOIS_RIPE_NET,
        "be" to "whois.dns.be",
        "bg" to "whois.register.bg",
        "bi" to "whois.nic.bi",
        "biz" to "whois.neulevel.biz",
        "bj" to "www.nic.bj",
        "br" to "whois.nic.br",
        "br.com" to WHOIS_FOREIGN_TLD,
        "bt" to "whois.netnames.net",
        "by" to "whois.cctld.by",
        "bz" to "whois2.afilias-grs.net",
        "ca" to "whois.cira.ca",
        "cat" to "whois.cat",
        "cc" to "whois.nic.cc",
        "cd" to "whois.nic.cd",
        "ch" to "whois.nic.ch",
        "ck" to "whois.nic.ck",
        "cl" to "whois.nic.cl",
        "cn" to "whois.cnnic.net.cn",
        "cn.com" to WHOIS_FOREIGN_TLD,
        "co" to "whois.nic.co",
        "co.nl" to "whois.co.nl",
        "coop" to "whois.nic.coop",
        "cx" to "whois.nic.cx",
        "cy" to WHOIS_RIPE_NET,
        "cz" to "whois.nic.cz",
        "de" to "whois.denic.de",
        "dk" to "whois.dk-hostmaster.dk",
        "dm" to "whois.nic.cx",
        "dz" to "whois.nic.dz",
        "edu" to "whois.educause.net",
        "ee" to "whois.tld.ee",
        "eg" to WHOIS_RIPE_NET,
        "es" to "whois.nic.es",
        "eu" to "whois.eu",
        "eu.com" to WHOIS_FOREIGN_TLD,
        "fi" to "whois.ficora.fi",
        "fo" to "whois.nic.fo",
        "fr" to "whois.nic.fr",
        "gb" to WHOIS_RIPE_NET,
        "gb.com" to "whois.networksolutions.com",
        "gb.net" to WHOIS_FOREIGN_TLD,
        "qc.com" to WHOIS_FOREIGN_TLD,
        "ge" to WHOIS_RIPE_NET,
        "gl" to "whois.nic.gl",
        "gm" to WHOIS_RIPE_NET,
        "gov" to "whois.nic.gov",
        "gr" to WHOIS_RIPE_NET,
        "gs" to "whois.nic.gs",
        "hk" to "whois.hknic.net.hk",
        "hm" to "whois.registry.hm",
        "hn" to "whois.nic.hn",
        "hr" to "whois.dns.hr",
        "hu" to "whois.nic.hu",
        "hu.com" to WHOIS_FOREIGN_TLD,
        "id" to "whois.pandi.or.id",
        "ie" to "whois.domainregistry.ie",
        "il" to "whois.isoc.org.il",
        "in" to "whois.inregistry.net",
        "info" to "whois.afilias.info",
        "int" to "whois.isi.edu",
        "io" to "whois.nic.io",
        "iq" to "vrx.net",
        "ir" to "whois.nic.ir",
        "is" to "whois.isnic.is",
        "it" to "whois.nic.it",
        "je" to "whois.je",
        "jobs" to "jobswhois.verisign-grs.com",
        "jp" to "whois.jprs.jp",
        "ke" to "whois.kenic.or.ke",
        "kg" to "whois.domain.kg",
        "kr" to "whois.nic.or.kr",
        "la" to "whois.nic.la",
        "li" to "whois.nic.li",
        "lt" to "whois.domreg.lt",
        "lu" to "whois.restena.lu",
        "lv" to "whois.nic.lv",
        "ly" to "whois.nic.ly",
        "ma" to "whois.iam.net.ma",
        "mc" to WHOIS_RIPE_NET,
        "md" to "whois.nic.md",
        "me" to "whois.nic.me",
        "mil" to "whois.nic.mil",
        "mk" to WHOIS_RIPE_NET,
        "mobi" to "whois.dotmobiregistry.net",
        "ms" to "whois.nic.ms",
        "mt" to WHOIS_RIPE_NET,
        "mu" to "whois.nic.mu",
        "mx" to "whois.nic.mx",
        "my" to "whois.mynic.net.my",
        "name" to "whois.nic.name",
        "net" to "whois.verisign-grs.com",
        "nf" to "whois.nic.nf",
        "ng" to "whois.nic.net.ng",
        "nl" to "whois.domain-registry.nl",
        "no" to "whois.norid.no",
        "no.com" to WHOIS_FOREIGN_TLD,
        "nu" to "whois.nic.nu",
        "nz" to "whois.srs.net.nz",
        "co.nz" to "whois.srs.net.nz",
        "org" to "whois.pir.org",
        "pl" to "whois.dns.pl",
        "pr" to "whois.nic.pr",
        "pro" to "whois.registrypro.pro",
        "pt" to "whois.dns.pt",
        "pw" to "whois.nic.pw",
        "ro" to "whois.rotld.ro",
        "ru" to "whois.tcinet.ru",
        "sa" to "saudinic.net.sa",
        "sa.com" to WHOIS_FOREIGN_TLD,
        "sb" to "whois.nic.net.sb",
        "sc" to "whois2.afilias-grs.net",
        "se" to "whois.nic-se.se",
        "se.com" to WHOIS_FOREIGN_TLD,
        "se.net" to WHOIS_FOREIGN_TLD,
        "sg" to "whois.nic.net.sg",
        "sh" to "whois.nic.sh",
        "si" to "whois.arnes.si",
        "sk" to "whois.sk-nic.sk",
        "sm" to "whois.nic.sm",
        "st" to "whois.nic.st",
        "so" to "whois.nic.so",
        "su" to "whois.tcinet.ru",
        "tc" to "whois.adamsnames.tc",
        "tel" to "whois.nic.tel",
        "tf" to "whois.nic.tf",
        "th" to "whois.thnic.net",
        "tj" to "whois.nic.tj",
        "tk" to "whois.nic.tk",
        "tm" to "whois.nic.tm",
        "tn" to "whois.ati.tn",
        "to" to "whois.tonic.to",
        "tp" to "whois.domains.tl",
        "tr" to "whois.nic.tr",
        "travel" to "whois.nic.travel",
        "tw" to "whois.twnic.net.tw",
        "tz" to "whois.tznic.or.tz",
        "ua" to "whois.ua",
        "uk" to "whois.nic.uk",
        "uk.com" to WHOIS_FOREIGN_TLD,
        "uk.net" to WHOIS_FOREIGN_TLD,
        "ac.uk" to "whois.ja.net",
        "gov.uk" to "whois.ja.net",
        "us" to "whois.nic.us",
        "us.com" to WHOIS_FOREIGN_TLD,
        "uy" to "nic.uy",
        "uy.com" to WHOIS_FOREIGN_TLD,
        "uz" to "whois.cctld.uz",
        "va" to WHOIS_RIPE_NET,
        "vc" to "whois2.afilias-grs.net",
        "ve" to "whois.nic.ve",
        "vg" to "whois.nic.vg",
        "ws" to "whois.website.ws",
        "xxx" to "whois.nic.xxx",
        "yu" to WHOIS_RIPE_NET,
        "za.com" to WHOIS_FOREIGN_TLD,
        "com" to "www.iana.org",
        "aero" to "whois.aero",
        "arpa" to "whois.iana.org",
        "asia" to "whois.nic.asia",
        "at" to "whois.nic.at",
        "be" to "whois.dns.be",
        "biz" to "whois.biz",
        "br" to "whois.registro.br",
        "ca" to "whois.cira.ca",
        "cc" to "whois.nic.cc",
        "cn" to "whois.cnnic.net.cn",
        "com" to "whois.verisign-grs.com",
        "gov" to "whois.nic.gov",
        "in" to "whois.inregistry.net",
        "info" to "whois.afilias.info",
        "int" to "whois.iana.org",
        "is" to "whois.isnic.is",
        "it" to "whois.nic.it",
        "jobs" to "jobswhois.verisign-grs.com",
        "me" to "whois.meregistry.net",
        "mil" to "whois.nic.mil",
        "mobi" to "whois.dotmobiregistry.net",
        "museum" to "whois.museum",
        "name" to "whois.nic.name",
        "net" to "whois.verisign-grs.net",
        "org" to "whois.pir.org",
        "pro" to "whois.registrypro.pro",
        "tc" to "whois.adamsnames.tc",
        "tel" to "whois.nic.tel",
        "travel" to "whois.nic.travel",
        "co.uk" to "whois.nic.uk",
        "org.uk" to "whois.nic.uk",
        "us" to "whois.nic.us",
        "wang" to "whois.nic.wang",
        "top" to "whois.nic.top",
        "ren" to "whois.nic.ren",
        "xn--55qx5d" to WHOIS_CHINESE_TLD2,
        "公司" to WHOIS_CHINESE_TLD2,
        "中国" to "whois.cnnic.net.cn",
        "xn--fiqs8s" to "whois.cnnic.net.cn",
        "网络" to WHOIS_CHINESE_TLD2,
        "xn--io0a7i" to WHOIS_CHINESE_TLD2,
        "政务" to WHOIS_CHINESE_TLD2,
        "xn--zfr164b" to WHOIS_CHINESE_TLD2,
        "公益" to WHOIS_CHINESE_TLD2,
        "xn--55qw42g" to WHOIS_CHINESE_TLD2,
        "集团" to "whois.nic.wang",
        "xn--3bst00m" to "whois.nic.wang",
        "新闻" to WHOIS_CHINESE_TLD,
        "网店" to WHOIS_CHINESE_TLD,
        "时尚" to WHOIS_CHINESE_TLD,
        "商标" to WHOIS_CHINESE_TLD,
        "我爱你" to WHOIS_CHINESE_TLD,
        "网址" to WHOIS_CHINESE_TLD,
        "中信" to WHOIS_CHINESE_TLD,
        "八卦" to WHOIS_CHINESE_TLD,
        "商城" to WHOIS_CHINESE_TLD,
        "餐厅" to WHOIS_CHINESE_TLD,
        "娱乐" to WHOIS_CHINESE_TLD,
        "慈善" to WHOIS_CHINESE_TLD,
        "手机" to "whois.afilias-srs.net",
        "xn--kput3i" to "whois.afilias-srs.net",
        "ws" to "whois.website.ws",
        "xxx" to "whois.nic.xxx",
        "ac" to "whois.nic.ac",
        "af" to "whois.nic.af",
        "as" to "whois.nic.as",
        "ag" to "whois.nic.ag",
        "am" to "whois.amnic.net",
        "at" to "whois.nic.at",
        "cm" to "whois.netcom.cm",
        "com.de" to "whois.denic.de",
        "ec" to "whois.nic.ec",
        "fm" to "whois.nic.fm",
        "gg" to "whois.gg",
        "gy" to "whois.registry.gy",
        "mg" to "whois.nic.mg",
        "pe" to "kero.yachay.pe",
        "ph" to "dot.ph",
        "sg" to "whois.sgnic.sg",
        "sx" to "whois.sx",
        "tl" to "whois.nic.tl",
        "tv" to "tvwhois.verisign-grs.com",
        "gb" to "whois.1api.net",
        "site" to WHOIS_FOREIGN_TLD,
        "website" to "whois.nic.website",
        "web" to WHOIS_FOREIGN_TLD,
        "home" to WHOIS_FOREIGN_TLD,
        "space" to "whois.nic.space",
        "online" to WHOIS_FOREIGN_TLD,
        "press" to "whois.nic.press",
        "tech" to "whois.nic.tech",
        "store" to WHOIS_FOREIGN_TLD,
        "music" to WHOIS_FOREIGN_TLD,
        "shop" to WHOIS_FOREIGN_TLD,
        "mk" to "whois.marnet.mk",
        "gw" to "whois.nic.gw",
        "mp" to "whois.nic.mp",
        "ml" to "whois.dot.ml",
        "tk" to "whois.dot.tk",
        "cf" to "whois.dot.cf",
        "ga" to "whois.my.ga",
        "gq" to "whois.dominio.gq",
        "sg" to "whois.sgnic.sg",
        "mo" to "whois.monic.mo",
        "news" to "whois.rightside.co",
        "bi" to "whois1.nic.bi",
        "tn" to "whois.ati.tn"
    )

fun String.whoisSocket(): String {
    val server = whoisServers[substringAfterLast(".")]
    val socket = Socket(server, 43)
    return socket.getOutputStream().use {
        it.write("$this\r\n".toByteArray())
        socket.getInputStream().use { it.readBytes().decodeToString() }
    }
}
